package signalprocessing;

import ikelib.ChannelData;
import ikelib.IntegrateAccelaration;
import ikelib.Median;
import ikelib.PlotColor;
import ikelib.wintime;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import wcg.SignalProcessingInterface;
import wcg.stateChangeNotify;
import ikeuilib.*;

/**
 * 
 */

/**
 * 積分を表示する。　加速度＞速度＞変位の表示
 * 
 * @author ikechan
 *
 */
public class PanelIntegration extends SignalProcessingPanelBasic implements stateChangeNotify,SignalProcessingInterface,PlotPanelCollectionInterface,
						PanelControlYScaleInterface,PanelControlXScaleInterface, SignalprocessingPanelInterface {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JList ListChannel;
	protected PlotPaneCollection PlotCollection=null;
	private JCheckBox checkBoxAccelaration;
	private JCheckBox chckbxVelocity;
	private JCheckBox checkBoxDisplace;
	private JCheckBox chckbxAccelarationraw;


	/**
	 * 
	 */
	public PanelIntegration() {
		super();
		setLayout(new BorderLayout(0, 0));
		setPreferredSize(new Dimension(500,500));

		PlotPanel panelIntegration = new PlotPanel(Col);
		add(panelIntegration, BorderLayout.CENTER);
		panelIntegration.setLayout(new BorderLayout(0, 0));

		JPanel panelControlPanelIntegration = new JPanel();
		panelIntegration.add(panelControlPanelIntegration, BorderLayout.WEST);

		panelControlPanelIntegration.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		panelControlPanelIntegration.setLayout(null);
		panelControlPanelIntegration.setPreferredSize(new Dimension(210, 600));

		JPanel panelChannelandCalc = new JPanel();
		panelChannelandCalc.setBorder(new TitledBorder(null, "Channel & Calclation", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panelChannelandCalc.setBounds(7, 14, 189, 159);
		panelControlPanelIntegration.add(panelChannelandCalc);
		panelChannelandCalc.setLayout(null);

		checkBoxDisplace = new JCheckBox("Displacement");
		checkBoxDisplace.setBounds(74, 121, 107, 21);
		panelChannelandCalc.add(checkBoxDisplace);
		checkBoxDisplace.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				onConfChange();
			}
		});
		checkBoxDisplace.setToolTipText("Integrated of Velocity.");

		chckbxVelocity = new JCheckBox("Velocity");
		chckbxVelocity.setBounds(74, 96, 107, 21);
		panelChannelandCalc.add(chckbxVelocity);
		chckbxVelocity.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				onConfChange();
			}
		});
		chckbxVelocity.setToolTipText("Integrated of Acc.");

		checkBoxAccelaration = new JCheckBox("Accelaration");
		checkBoxAccelaration.setBounds(74, 73, 107, 21);
		panelChannelandCalc.add(checkBoxAccelaration);
		checkBoxAccelaration.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				onConfChange();
			}
		});
		checkBoxAccelaration.setToolTipText("Acc. data compensated base line.");
		checkBoxAccelaration.setSelected(true);

		chckbxAccelarationraw = new JCheckBox("Accel.(RAW)");
		chckbxAccelarationraw.setBounds(74, 27, 107, 21);
		panelChannelandCalc.add(chckbxAccelarationraw);
		chckbxAccelarationraw.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				onConfChange();
			}
		});
		chckbxAccelarationraw.setToolTipText("Display original (accelaration) data.");

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(12, 27, 58, 115);
		panelChannelandCalc.add(scrollPane);

		ListChannel = new JList();
		scrollPane.setViewportView(ListChannel);
		ListChannel.addListSelectionListener(new ListSelectionListener() {
			// ＣＨセレクションが変更されたとき
			public void valueChanged(ListSelectionEvent arg0) {
				if(!arg0.getValueIsAdjusting()){
					onConfChange();
				}
			}

		});
		/*
		 * Ｙスケールコントロール小パネルを表示する
		 */
		PanelControlYScaleConfiguration confyscale = new PanelControlYScaleConfiguration();
		
		PanelControlYScale panelControlYScale = new PanelControlYScale(confyscale);
		panelControlYScale.setLocation(7, 239);
		panelControlYScale.addParent(this);
		panelControlPanelIntegration.add(panelControlYScale);


		PlotPanelCollectionConfiguration conf = new PlotPanelCollectionConfiguration();
		PlotCollection = new PlotPaneCollection(Col,conf);
		panelIntegration.add(PlotCollection, BorderLayout.CENTER);
		PlotCollection.setUp(this,AccViewCh,Plot,Col);

		/*
		 * Xスケールコントロール小パネルを表示する
		 */
		PanelControlXScaleConfiguration confx  = new PanelControlXScaleConfiguration();
		confx.TruncateButton = false;
		PanelControlXScale panelControlXScale = new PanelControlXScale(confx);
		panelControlXScale.setLocation(7, 371);
		panelControlXScale.addParent(this);
		panelControlPanelIntegration.add(panelControlXScale);
		
		JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(null, "Display", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panel.setBounds(7, 179, 191, 57);
		panelControlPanelIntegration.add(panel);
				panel.setLayout(null);
		
				// とりあえず全部を強制的に再描画するボタン　
				JButton btnRepaint = new JButton("ReDraw");
				btnRepaint.setBounds(95, 19, 84, 21);
				panel.add(btnRepaint);
				btnRepaint.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						repaintAllComponent();
					}
				});

	

		{
			//addChannelPanel(0);	// test
		}
		initial();

	}
	/**
	 * チャンネルリストの選択ＣＨ・全ＣＨを得る
	 * @param selected　true=選択ＣＨ、false=全ＣＨ
	 * @return
	 */
	private Integer[] getChannelList(boolean selected){
		if(ListChannel==null) return null;
		ListModel model = ListChannel.getModel(); //@
		int max = model.getSize();
		LinkedList<Integer> lst = new LinkedList<Integer>();
		for(int i=0;i<max;i++){
			boolean disp = ListChannel.isSelectedIndex(i);
			String ms = (String)ListChannel.getModel().getElementAt(i);
			int ch = Integer.valueOf(ms,16);	
			if(selected && disp){
				lst.add(ch);
			}
			else if(!selected){
				lst.add(ch);
			}
		}
		Integer[] ret = lst.toArray(new Integer[0]);
		if(lst.size()<=0) return null;
		return ret;
	}


	protected void onViewChange(){ 
		repaintAllComponent();
	}
	enum CalcType { RAW, DECIMATION , Accelaration, Velocity , Displacement };
	private static final int CALCTYPE_RAW 				= 0x01 << 0;
	//private static final int CALCTYPE_DECIMATE 			= 0x01 << 1;
	private static final int CALCTYPE_Accelaration 		= 0x01 << 2;
	private static final int CALCTYPE_Velocity 			= 0x01 << 3;
	private static final int CALCTYPE_Displacement 		= 0x01 << 4;

	/**
	 * 計算オプションを表す ＩＤを得る
	 * @return
	 */
	private Integer[] getSubId(boolean getAllOption){
		LinkedList<Integer> lst = new LinkedList<Integer>();
		if(chckbxAccelarationraw==null) return null;
		if(chckbxAccelarationraw.isSelected() || getAllOption){
			lst.add(CALCTYPE_RAW);
		}
//		if(chckbxDecimate==null) return null;
//		if(chckbxDecimate.isSelected()|| getAllOption){
//			lst.add(CALCTYPE_DECIMATE);
//		}
		if(checkBoxAccelaration==null) return null;
		if(checkBoxAccelaration.isSelected()|| getAllOption){
			lst.add(CALCTYPE_Accelaration);
		}
		if(chckbxVelocity==null) return null;
		if(chckbxVelocity.isSelected()|| getAllOption){
			lst.add(CALCTYPE_Velocity);
		}
		if(checkBoxDisplace==null) return null;
		if(checkBoxDisplace.isSelected()|| getAllOption){
			lst.add(CALCTYPE_Displacement);
		}
		if(lst.size()<=0) return null;
		Integer[] ret = lst.toArray(new Integer[0]);
		return ret;
	}

	/**
	 *  1つのＣＨのグラフエリアを生成する。
	 * @param Panel_Channels
	 * @param id
	 */
	private void addChannelPanel(int id,int subid) {

		if(subid ==0) return;

		double[] data = getChannelRawData(id);
		if(data == null){
			//System.out.println("fail to getChannelRawData: SignalProcessingPain " + id + subid);
			String mes = String.format("No data found for CH = %04x", id);
			JOptionPane.showMessageDialog(null, "No data found" + mes, mes,  JOptionPane.ERROR_MESSAGE, null);
			return;
		}
		int samplerate=getRawSampleRate(id);;
		if(0 != (subid & CALCTYPE_RAW)){
			samplerate = getRawSampleRate(id);
			if(samplerate<=0) return;
			String name = getDisplayName(CalcType.RAW);
			//addChannelPanel(Panel_Channels,id | CALCTYPE_RAW<<16 ,name, data, samplerate);
			PlotCollection.addChannelPanel(id | CALCTYPE_RAW<<16 ,name, data, samplerate,Data);
		}
//		if(0 != (subid & CALCTYPE_DECIMATE)){
//			// TODO: Decimationの種類を増やす
//			samplerate = getRawSampleRate(id);
//			if(samplerate<=0) return;
//			Median med =  new Median(samplerate);
//			Double[] in = new Double[data.length];
//			for(int i=0;i<data.length;i++) in[i] = data[i];
//			LinkedList<Double> r= med.decimate(in);
//			Double[] t = r.toArray(new Double[1]);
//			data = new double[t.length];
//			for(int i=0;i<data.length;i++) data[i] = t[i];
//			samplerate = 1;
//			String name = getDisplayName(CalcType.DECIMATION);
//			//addChannelPanel(Panel_Channels,id | CALCTYPE_DECIMATE<<16, name, data, samplerate);
//			PlotCollection.addChannelPanel(id | CALCTYPE_DECIMATE<<16, name, data, samplerate,Data);
//		}
		if(0 != (subid & (CALCTYPE_Accelaration | CALCTYPE_Velocity | CALCTYPE_Displacement))){
			double t = 1/(double)samplerate;
			IntegrateAccelaration intd = new IntegrateAccelaration(t);
			intd.Calc(data,data[0]); // 最初のデータを０にする
			if(0 != (subid & CALCTYPE_Accelaration)){
				String name = getDisplayName(CalcType.Accelaration);
				//addChannelPanel(Panel_Channels,id | CALCTYPE_Accelaration<<16, name, intd.getAcs(), samplerate);
				PlotCollection.addChannelPanel(id | CALCTYPE_Accelaration<<16, name, intd.getAcs(), samplerate,Data);
			}
			if(0 != (subid & CALCTYPE_Velocity)){
				String name = getDisplayName(CalcType.Velocity);
				//addChannelPanel(Panel_Channels,id| CALCTYPE_Velocity<<16, name, intd.getVel(), samplerate);
				PlotCollection.addChannelPanel(id| CALCTYPE_Velocity<<16, name, intd.getVel(), samplerate,Data);
			}
			if(0 != (subid & CALCTYPE_Displacement)){
				String name = getDisplayName(CalcType.Displacement);
				//addChannelPanel(Panel_Channels,id| CALCTYPE_Displacement<<16 ,name, intd.getDsp(), samplerate);
				PlotCollection.addChannelPanel(id| CALCTYPE_Displacement<<16 ,name, intd.getDsp(), samplerate,Data);
			}
		}
	}
	/**
	 * ＣＨリストをセットする
	 */
	public void doGetChannel(){
		ListChannel.removeAll();
		DefaultListModel model = new DefaultListModel(); //@
		//Iterator<Integer> ite = Data.getChannel().iterator();
		Iterator<Integer> ite = Data.iteratorChannel();
		while(ite.hasNext()){
			int ch = ite.next();
			String channel = new String();
			channel=String.format("%01X%01X%01X%01X", (ch>>12)&0xf,(ch>>8)&0xf,(ch>>4)&0xf,(ch>>0)&0xf);
			model.addElement(channel);
		}
		ListChannel.setModel(model);
	}
	private void initial(){
		Col.setColorMode(PlotColor.COLOR_COLOR_BLACK_BACK);
	}
	/**
	 * @param type
	 * @return
	 */
	private String getDisplayName(CalcType type) {
		String name = new String();
		switch(type){
		case RAW:
			name = "Accelaration(RAW)";
			break;
		case DECIMATION:
			name = "Accelaration(Decimated)";
			break;
		case Accelaration:
			name = "Accelaration";
			break;
		case Velocity:
			name = "Velocity";
			break;
		case Displacement:
			name = "Displacement";
			break;
		default:
		}
		return name;
	}
	/* (non-Javadoc)
	 * @see stateChangeNotify#onStateChange(int)
	 */
	@Override
	public void onStateChange(int hint) {

	}


	/**
	 * すべてのコンポーネントを再描画させる。
	 */
	@Override
	public void repaintAllComponent(){
		PlotCollection.repaintAllComponent();
	}


	/**
	 * @return
	 */
	public Dimension getPanelViewSize() {
		return PlotCollection.getSize();
	}

	/**
	 * @param g
	 */
	public void panelViewprintAll(Graphics2D g) {
		PlotCollection.paintAll(g);
	}

	/**
	 * @param colorColorBlackBack
	 */
	public void setColorMode(int colorColorBlackBack) {
		Col.setColorMode(colorColorBlackBack);

	}
	/* (non-Javadoc)
	 * @see SignalProcessingPanelBasic#updateChannel()
	 */
	@Override
	public void updateChannel() {
		Integer[] sel2 = getChannelList(true);		// すべてのＣＨ
		Integer[] sel = getChannelList(false); 		// 選択されているＣＨ
		Integer[] subid = getSubId(true); 			// すべてのオプションを得る
		Integer[] subid2 = getSubId(false); 		// 選択されているオプションを得る
		if(PlotCollection != null){
			PlotCollection.onUpdateChannelMultiPlot(sel,sel2,subid2,subid);
			revalidate();
		}
	}
	/* (non-Javadoc)
	 * @see PlotPanelCollectionInterface#onSetData(int, int)
	 */
	@Override
	public boolean onSetData(int id, int subid) {
		addChannelPanel(id,subid);
		return true;
	}
	/* (non-Javadoc)
	 * @see PlotPanelCollectionInterface#onInitView(int)
	 */
	@Override
	public boolean onInitView(int hint) {
		doYSpanAuto(PlotPane.ScaleAuto_FITCenter);
		onViewChange();
		
		return true;
	}
	/* (non-Javadoc)
	 * @see PlotPanelCollectionInterface#onSetData(java.lang.Integer[])
	 */
	@Override
	public boolean onSetData(Integer[] a) {
		return false;
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpanTruncate(int)
	 */
	@Override
	public void ySpanTruncate(int digit) {
		doYSpanTruncate(digit);
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpanSingle(int)
	 */
	@Override
	public void ySpanSingle(int ratio) {
		doYSpanSingle(ratio);
		
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpanAuto(int)
	 */
	@Override
	public void ySpanAuto(int mode) {
		doYSpanAuto(mode);
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpanShift(int)
	 */
	@Override
	public void ySpanShift(int ratio) {
		doYSpanShift(ratio);
		
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpanSingleGroup(int)
	 */
	@Override
	public void ySpanSingleGroup(int mode) {
		doYSpanSingleGroup(mode);
		
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlYScaleInterface#ySpan(int)
	 */
	@Override
	public void ySpan(int ratio) {
		doYSpan(ratio);
		
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlXScaleInterface#xSpanZoom(int)
	 */
	@Override
	public void xSpanZoom(int ratio) {
		doTSpanZoom(ratio);
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlXScaleInterface#xShift(int)
	 */
	@Override
	public void xShift(int ratio) {
		doTShift(ratio);
	}
	/* (non-Javadoc)
	 * @see ikeuilib.PanelControlXScaleInterface#xSpanFull()
	 */
	@Override
	public void xSpanFull() {
		doTSpanAuto();
		
	}
	/* (non-Javadoc)
	 * @see signalprocessing.PanelControlXScaleInterface#xSpanTruncate(int)
	 */
	@Override
	public void xSpanTruncate(int mode) {
		
	}
	/* (non-Javadoc)
	 * @see signalprocessing.PanelControlYScaleInterface#ySpan(double, double)
	 */
	@Override
	public void ySpan(double max, double min) {
		doYSpan(max,min);
		
	}
}
